1. Intro

์ด๋ฒˆ์—๋Š” leaflet๊ณผ crosstalk์„ ํ™œ์šฉํ•˜์—ฌ ์ง€๋„ ์‹œ๊ฐํ™” ๋ฐ ์œ„์ ฏ ๊ฐ„ ์ƒํ˜ธ์ž‘์šฉ์„ ๋‹ค๋ค„๋ณผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. leaflet์€ ์ง€๋„ ์‹œ๊ฐํ™”๋ฅผ ์œ„ํ•œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ์˜คํ”ˆ์†Œ์Šค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ Leaflet.js์˜ R ์ธํ„ฐํŽ˜์ด์Šค์ž…๋‹ˆ๋‹ค. crosstalk์€ ํ•˜๋‚˜์˜ ๊ณต์œ  ๋ฐ์ดํ„ฐ๋ฅผ ์ค‘์‹ฌ์œผ๋กœ ์—ฌ๋Ÿฌ ์œ„์ ฏ๋“ค์„ ์—ฐ๊ฒฐํ•˜๋ฉฐ, linked brushing, filtering ๋“ฑ์˜ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฒˆ ์‹ค์Šต์—์„œ ์‚ฌ์šฉํ•˜๋Š” crosstalk, leaflet, d3scatter ํŒจํ‚ค์ง€๋Š” ์•„๋ž˜ ๊นƒํ—ˆ๋ธŒ์—์„œ ๋ฐ›์•„์ฃผ์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

devtools::install_github("dmurdoch/leaflet@crosstalk4")
devtools::install_github("rstudio/leaflet")
devtools::install_github("jcheng5/d3scatter")

2. Leaflet

2.1. ์ง€๋„ ๊ทธ๋ฆฌ๊ธฐ

์ง€๋„๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ฝ”๋“œ๋Š” ๋งค์šฐ ๊ฐ„๋‹จํ•˜๋ฉฐ ์ง๊ด€์ ์ž…๋‹ˆ๋‹ค. leaflet() %>% addTiles()๋กœ ์ง€๋„๋ฅผ ๊ทธ๋ฆฌ๊ณ  mymap์ด๋ผ๋Š” ๋ณ€์ˆ˜์— ์ €์žฅํ•˜์˜€์Šต๋‹ˆ๋‹ค. ์™ผ์ชฝ ์ง€๋„๋Š” ์ด ๊ฒฐ๊ณผ๋ฅผ ๊ทธ๋Œ€๋กœ ์ถœ๋ ฅํ•œ ๊ฒƒ์ด๊ณ , ์˜ค๋ฅธ์ชฝ ์ง€๋„๋Š” setView() ํ•จ์ˆ˜๋กœ ์ขŒํ‘œ์™€ ํ™•๋Œ€๋ฅผ ์ง€์ •ํ•˜์—ฌ ์ถœ๋ ฅํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. crosstalk::bscols() ํ•จ์ˆ˜๋Š” ๋‹จ์ˆœํžˆ ์ง€๋„๋ฅผ ๋‚˜๋ž€ํžˆ ๋ฐฐ์—ดํ•˜๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉํ•˜์˜€์œผ๋ฉฐ, ์ง€๋„์—๋Š” ์•„๋ฌด๋Ÿฐ ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

library(tidyverse)
library(leaflet)
mymap = leaflet() %>% addTiles()
crosstalk::bscols(
  mymap,
  mymap %>% setView(126.982, 37.5502, zoom=10)
)

2.2. ์ง€๋„์— ์  ์ฐ๊ธฐ

leaflet์„ ํ†ตํ•ด์„œ ์†์‰ฝ๊ฒŒ ์ง€๋„๋ฅผ ๊ทธ๋ฆด ์ˆ˜ ์žˆ์„ ๋ฟ ์•„๋‹ˆ๋ผ, ์ง€๋„ ์œ„์— ๋ฐ์ดํ„ฐ๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ์€ ์ง€๋„ ์œ„์— ์ ์„ ํ‘œํ˜„ํ•˜๋Š” ์˜ˆ์ œ๋“ค์ž…๋‹ˆ๋‹ค. ์œ„๊ฒฝ๋„๋กœ ํ‘œํ˜„๋œ ์ขŒํ‘œ๊ฐ€ ์žˆ๋‹ค๋ฉด ์†์‰ฝ๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ์ง€๋„ ์œ„์— ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

points1 = mymap %>% 
  addMarkers(lng=c(126.882, 126.982, 127.082),
             lat=c(37.4502, 37.5502, 37.6502),
             label=c('์˜ˆ์‹œ1','์˜ˆ์‹œ2','์˜ˆ์‹œ3'))

points2 = mymap %>%
  addMarkers(data = quakes[1:20,], lng=~long, lat=~lat, label=~as.character(mag))

crosstalk::bscols(points1,points2)

2.2. ์ง€๋„์— ๋„ํ˜• ๊ทธ๋ฆฌ๊ธฐ

์ง€๋ฆฌ ๋ฐ์ดํ„ฐ๋Š” .shp, .json, .csv ๋“ฑ ๋‹ค์–‘ํ•œ ํ˜•ํƒœ๋กœ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฒˆ์—๋Š” .json ํ˜•์‹์„ ํŒŒ์ผ์„ ๊ฐ€์ง€๊ณ  ์‹ค์Šต์„ ์ง„ํ–‰ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์‹ค์Šต์— ์‚ฌ์šฉํ•  ๋ฐ์ดํ„ฐ๋Š” 2016๋…„ ๊ตญํšŒ์˜์› ์ด์„ ์˜ ์„œ์šธ ์ง€์—ญ ๊ฐœํ‘œ๊ฒฐ๊ณผ ๋ฐ์ดํ„ฐ์ž…๋‹ˆ๋‹ค. ์ „์ฒ˜๋ฆฌ geojsonioํŒจํ‚ค์ง€๋ฅผ ํ†ตํ•ด์„œ SpatialPolygonsDataFrame ํด๋ž˜์Šค๋กœ ํŒŒ์ผ์„ ์ฝ์–ด์˜ต๋‹ˆ๋‹ค. SpatialPolygonsDataFrame์€ ์ขŒํ‘œ๊ณ„, ํด๋ฆฌ๊ณค ์ขŒํ‘œ ๋“ฑ์˜ ์ง€๋ฆฌ์ •๋ณด์™€ ์ผ๋ฐ˜์ ์ธ ๋ฐ์ดํ„ฐํ”„๋ ˆ์ž„์„ ๊ฒฐํ•ฉํ•ด๋†“์€ ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค. election@polygons๋ฅผ ํ†ตํ•ด์„œ ํด๋ฆฌ๊ณค ๋ฆฌ์ŠคํŠธ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ณ , election@data๋ฅผ ํ†ตํ•ด์„œ ๋ฐ์ดํ„ฐํ”„๋ ˆ์ž„์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

election  = geojsonio::geojson_read("data/election.json", what = "sp")

cat("class(election) : ", class(election))
## class(election) :  SpatialPolygonsDataFrame
cat("class(election@polygons) : ", class(election@polygons))
## class(election@polygons) :  list
cat("class(election@data) : ", class(election@data))
## class(election@data) :  data.frame
# ๋ฐ์ดํ„ฐํ”„๋ ˆ์ž„์— ๊ฐ„๋‹จํ•œ ์ „์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ค€ ์˜ˆ์‹œ
colnames(election@data) = colnames(election@data) %>% str_replace(" ","")

์ง€๋„์— ํด๋ฆฌ๊ณค์„ ํ‘œํ˜„ํ•˜๋Š” ๊ฒƒ์€ ์ ์„ ์ฐ๋Š” ์ผ๋งŒํผ์ด๋‚˜ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. ์™ผ์ชฝ ์˜ˆ์ œ์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋“ฏ์ด addPolygons()์— ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•ด์ฃผ๋Š” ๊ฒƒ๋งŒ๋กœ ํด๋ฆฌ๊ณค์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์›ํ•˜๋Š” ๋ณ€์ˆ˜๋ฅผ ์ „๋‹ฌํ•˜๋ฉด ๊ฐ„๋‹จํ•œ ๋ผ๋ฒจ์„ ํ‘œํ˜„ํ•˜๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์˜ค๋ฅธ์ชฝ ์˜ˆ์ œ์—์„œ๋Š” ๊ฒฝ๊ณ„์„ ๊ณผ ํด๋ฆฌ๊ณค ๋‚ด๋ถ€ ์ƒ‰, ํ•˜์ด๋ผ์ดํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , ๋ผ๋ฒจ์„ ์ˆ˜์ •ํ•˜๊ณ , ์„ ๊ฑฐ๊ตฌ๋ณ„ ํด๋ฆฌ๋ผ์ธ๊ณผ ๋ฒ”๋ก€๋ฅผ ์ถ”๊ฐ€์ ์œผ๋กœ ๊ฒน์ณ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค. add~ ํ•จ์ˆ˜๋“ค์ด ํ•˜๋‚˜์˜ ๋ ˆ์ด์–ด๋ฅผ ๊ณต์œ ํ•œ๋‹ค๋ฉด, leaflet()์•ˆ์— ๋จผ์ € ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ๋„ ์ข‹์Šต๋‹ˆ๋‹ค.

poly1 = mymap %>% addPolygons(data=election,label=~๋‹น์„ )

# ์ง€๋„์— ์ƒ‰์„ ์ž…ํžˆ๊ธฐ ์œ„ํ•ด์„œ ํŒŒ๋ ˆํŠธ ์ƒ์„ฑ
pal = colorFactor(c("#0D7440", "#2A88C5",  "#C10D0D"), c("๊ตญ๋ฏผ์˜๋‹น", "๋”๋ถˆ์–ด๋ฏผ์ฃผ๋‹น","์ƒˆ๋ˆ„๋ฆฌ๋‹น"))

# ํˆดํŒ์— ๋‹ด์„ ์ •๋ณด ์ƒ์„ฑ
labs = lapply(seq(nrow(election@data)), function(i) {
  paste0( '<p><b>', election@data[i, "์„ ๊ฑฐ๊ตฌ"]," : ",election@data[i, "์๋ฉด๋™๋ช…"], '</b></p><p>', 
          "<b>๋‹น์„  : ", election@data[i, "๋‹น์„ "], '</b><p></p>', 
          "๊ตญ๋ฏผ์˜๋‹น : ", election@data[i, "๊ตญ๋ฏผ์˜๋‹น"],'</p><p>', 
          "๋”๋ถˆ์–ด๋ฏผ์ฃผ๋‹น : ", election@data[i, "๋”๋ถˆ์–ด๋ฏผ์ฃผ๋‹น"], '</p><p>',
          "์ƒˆ๋ˆ„๋ฆฌ๋‹น : ", election@data[i, "์ƒˆ๋ˆ„๋ฆฌ๋‹น"], '</p>') 
})

# ์„ ๊ฑฐ๊ตฌ ๊ฒฝ๊ณ„ ์ƒ์„ฑ
election_gu = maptools::unionSpatialPolygons(election, election$์„ ๊ฑฐ๊ตฌ)

poly2 = leaflet(election) %>%
  addTiles %>%
  addPolygons(
    # ํด๋ฆฌ๊ณค ๋‚ด๋ถ€
    fillColor = ~pal(๋‹น์„ ), fillOpacity = 0.5,
    # ํด๋ฆฌ๊ณค ๊ฒฝ๊ณ„
    weight = 1, opacity = 1, color = "white", dashArray=3,
    # ๋ผ๋ฒจ
    label=lapply(labs, htmltools::HTML),
    # ํ•˜์ด๋ผ์ดํŠธ
    highlightOptions = highlightOptions(
      color = "#00ff00", opacity = 1, weight = 2, fillOpacity = 1,
      bringToFront = T, sendToBack = T))%>%
  addLegend(pal = pal, values = ~๋‹น์„ , opacity = 0.7, title = NULL, position = "bottomright") %>%
  addPolylines(
    data=election_gu,
    weight = 1.5,
    opacity = 1,
    color = "black")

crosstalk::bscols(poly1, poly2)

3. Crosstalk

crosstalk์€ ํ•˜๋‚˜์˜ ๊ณต์œ  ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์—ฌ๋Ÿฌ ์œ„์ ฏ์„ ์—ฐ๋™์‹œํ‚ต๋‹ˆ๋‹ค. ๊ณต์œ  ๋ฐ์ดํ„ฐ๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์ด ๋ฐ์ดํ„ฐ๋กœ ํ”Œ๋กฏ์„ ๊ทธ๋ ค์ฃผ๊ธฐ๋งŒ ํ•˜๋ฉด ๋์ž…๋‹ˆ๋‹ค. crosstalk์€ ๋ฐ์ดํ„ฐํ”„๋ ˆ์ž„์„ ์ž…๋ ฅ์œผ๋กœ ๋ฐ›๋Š” HTML ์œ„์ ฏ๋“ค์—์„œ ์ž‘๋™ํ•˜๋ฉฐ, ์ฃผ์š”ํ•œ ํ•œ๊ณ„์ ๋“ค์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. ์ €์ž‘์ž๊ฐ€ ์ง์ ‘ HTML ์œ„์ ฏ์„ ์ ์ ˆํžˆ ์ˆ˜์ •ํ•ด์•ผ ํ•œ๋‹ค. crosstalk์€ ์Šค์Šค๋กœ ์œ„์ ฏ๋“ค์„ ์—ฐ๋™์‹œ์ผœ์ฃผ์ง€๋Š” ์•Š๋Š”๋‹ค.

  2. Crosstalk์€ ๊ฐœ๋ณ„ ๋ฐ์ดํ„ฐ ํฌ์ธํŠธ์— ๋Œ€ํ•ด์„œ๋งŒ ์ž‘๋™ํ•˜๋ฉฐ, ๋ฐ์ดํ„ฐ์˜ ๊ฒฐํ•ฉ์ด๋‚˜ ์š”์•ฝ์„ ํ‘œํ˜„ํ•˜๋Š” ์œ„์ ฏ๋“ค์—๋Š” ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด์„œ ๊ฐœ๋ณ„ ๋ฐ์ดํ„ฐ ํฌ์ธํŠธ๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ์‚ฐ์ ๋„์—๋Š” ์ ์šฉ๋  ์ˆ˜ ์žˆ์ง€๋งŒ, ํžˆ์Šคํ† ๊ทธ๋žจ์—๋Š” ์ ์šฉ๋  ์ˆ˜ ์—†๋‹ค.

  3. crosstalk์€ ํฐ ๋ฐ์ดํ„ฐ์— ์ ํ•ฉํ•˜์ง€ ์•Š๋‹ค. ๋ชจ๋“  ๋ฐ์ดํ„ฐ๊ฐ€ ๋ธŒ๋ผ์šฐ์ €์— ๋กœ๋“œ๋˜์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

3.1. Linked Brushing

Linked brushing์€ ํ•˜๋‚˜์˜ ํ”Œ๋กฏ์—์„œ ๋ฐœ์ƒํ•œ ๋ธŒ๋Ÿฌ์‹ฑ์„ ์—ฐ๊ฒฐ๋œ ๋‹ค๋ฅธ ํ”Œ๋กฏ๋“ค์—๋„ ์ ์šฉํ•˜๋Š” ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. ๋จผ์ € crosstalk::SharedData๋กœ ๋ฐ์ดํ„ฐํ”„๋ ˆ์ž„์„ ๊ฐ์‹ธ ์—ฌ๋Ÿฌ ์œ„์ ฏ๋“ค์„ ์—ฐ๊ฒฐํ•  ๊ณต์œ  ๋ฐ์ดํ„ฐ๋ฅผ ์ƒ์„ฑํ•ด์ค๋‹ˆ๋‹ค. ์ด ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•ด์„œ ๋‘ ๊ฐœ์˜ ๊ทธ๋ž˜ํ”„๋ฅผ ๊ทธ๋ ธ์Šต๋‹ˆ๋‹ค. ์ดํ›„ subplot ํ•จ์ˆ˜๋กœ ๋‘ ๊ฐœ์˜ ๊ทธ๋ž˜ํ”„๋ฅผ ๋ฌถ์–ด์ฃผ๊ณ , highlight์— "plotly_selected"๋ฅผ ์ „๋‹ฌํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ํ•œ ์ชฝ ํ”Œ๋กฏ์—์„œ ์ ๋“ค์„ ์„ ํƒํ•˜๋ฉด ๋‹ค๋ฅธ ์ชฝ ํ”Œ๋กฏ์—์„œ๋„ ํ•˜์ด๋ผ์ดํŠธ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. crosstalk์˜ SharedData๊ฐ€ ์•„๋‹Œ ์ผ๋ฐ˜ ๋ฐ์ดํ„ฐํ”„๋ ˆ์ž„์œผ๋กœ ํ”Œ๋กฏ์„ ๊ทธ๋ฆฐ๋‹ค๋ฉด ๋‹น์—ฐํžˆ ์ด ๊ธฐ๋Šฅ์€ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

library(crosstalk)
library(plotly)

# election@data๋ฅผ SharedData๋กœ ๊ฐ์‹ธ ๊ณต์œ  ๋ฐ์ดํ„ฐ๋ฅผ ์ƒ์„ฑ
shared_elec = SharedData$new(election@data)

p1 = plot_ly(shared_elec, x = ~์†Œ๋“, y = ~๋…ธ๋ นํ™”์ง€์ˆ˜, legendgroup=~๋‹น์„ ) %>%
  add_markers(color=~๋‹น์„ , colors=c("#0D7440", "#2A88C5",  "#C10D0D"), opacity=0.6)

p2 = plot_ly(shared_elec, x = ~์žฅ์• ๋“ฑ๊ธ‰๋ณ„.์žฅ์• ์ธํ˜„ํ™ฉ, y = ~๋ณด์œก์‹œ์„ค, legendgroup=~๋‹น์„ ) %>%
  add_markers(color=~๋‹น์„ , colors=c("#0D7440", "#2A88C5",  "#C10D0D"), opacity=0.6)

subplot(p1,p2) %>%
  layout(xaxis = list(title = "์†Œ๋“"),
         yaxis = list(title = "๋…ธ๋ นํ™”์ง€์ˆ˜"),
         xaxis2 = list(title = "์žฅ์• ์ธํ˜„ํ™ฉ"),
         yaxis2 = list(title = "๋ณด์œก์‹œ์„ค"),
         height=400, width=850) %>%
  highlight("plotly_selected")

crosstalk์€ ์„œ๋กœ ๋‹ค๋ฅธ ์ข…๋ฅ˜์˜ ์œ„์ ฏ๋“ค ๊ฐ„์—๋„ ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋งŒ, ์—ฌ๋Ÿฌ ์œ„์ ฏ๋“ค์ด ์„œ๋กœ ๋‹ค๋ฅธ ํด๋ž˜์Šค๋ฅผ ํ•„์š”๋กœ ํ•  ๊ฒฝ์šฐ์—๋Š” ์•ฝ๊ฐ„์˜ ์กฐ์ž‘์ด ๋” ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ์€ ์ง€๋„์™€ ์‚ฐ์ ๋„, ํ…Œ์ด๋ธ”์„ ์—ฐ๊ฒฐํ•œ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค. election์˜ ํด๋ž˜์Šค๋Š” SpatialPolygonsDataFame์ž…๋‹ˆ๋‹ค. plot_ly ํ•จ์ˆ˜๋Š” SpatialPolygonsDataFrame ํด๋ž˜์Šค์— ๋Œ€ํ•ด์„œ ์ž‘๋™ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ, election@data๋ฅผ ๋ณ„๋„๋กœ ๊ณต์œ  ๋ฐ์ดํ„ฐ๋กœ ๋งŒ๋“ค์–ด์ฃผ๋ฉด์„œ group=shared_elec$groupName() ์ธ์ž๋ฅผ ์ „๋‹ฌํ–ˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰ shared_elec๊ณผ shared_elec_df๊ฐ€ ํ•œ ๊ทธ๋ฃน์œผ๋กœ ์—ฐ๊ฒฐ๋œ ์ƒํƒœ์ด๊ณ , ์—ฐ๋™์ด ์ž˜ ์ด๋ฃจ์–ด์ง€๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. shared_elec_dt ์—ญ์‹œ ๊ทธ๋ฃน์„ ์ง€์ •ํ•˜์—ฌ ์—ฐ๋™์‹œ์ผฐ์Šต๋‹ˆ๋‹ค.

library(d3scatter)

shared_elec = SharedData$new(election)
shared_elec_df = SharedData$new(election@data, group=shared_elec$groupName())
shared_elec_dt = crosstalk::SharedData$new(election@data %>%
                 select(์„ ๊ฑฐ๊ตฌ,๋‹น์„ ,์๋ฉด๋™๋ช…,์†Œ๋“,๋…ธ๋ นํ™”์ง€์ˆ˜), group=shared_elec$groupName())

DT::datatable(shared_elec_dt, width="100%")
bscols(
  d3scatter(data=shared_elec_df, x=~์†Œ๋“,y=~๋…ธ๋ นํ™”์ง€์ˆ˜,color=~๋‹น์„ , height=300, width="100%"),
  d3scatter(data=shared_elec_df, x=~์žฅ์• ๋“ฑ๊ธ‰๋ณ„.์žฅ์• ์ธํ˜„ํ™ฉ,y=~์‚ฌ์—…์ฒด์ˆ˜,color=~๋‹น์„ , height=300, width="100%")
)
leaflet(shared_elec) %>%
  addProviderTiles("CartoDB.Positron") %>% 
  setView(126.982, 37.5502, zoom=10) %>%
  addPolygons(
    fillColor = ~pal(๋‹น์„ ),
    weight = 1,
    opacity = 1,
    color = "white",
    dashArray=3,
    fillOpacity = 0.5,
    label = lapply(labs, htmltools::HTML)) %>%
  addLegend(pal = pal, values = ~๋‹น์„ , opacity = 0.7, title = NULL, position = "bottomright") %>%
  addPolylines(
    data=election_gu,
    weight = 1.5,
    opacity = 1,
    color = "black")

3.2. Filtering

ํ•„ํ„ฐ๋ง์€ ๋ง ๊ทธ๋Œ€๋กœ ํŠน์ • ๋ฐ์ดํ„ฐ ํฌ์ธํŠธ๋ฅผ ํ•„ํ„ฐ๋งํ•˜๋Š” ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. ์˜ˆ์ œ์™€ ํ•จ๊ป˜ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

bscols(
  list(filter_checkbox("๋‹น์„ ", "๋‹น์„ ", shared_elec_df, ~๋‹น์„ , inline=T),
       filter_slider("์†Œ๋“", "์†Œ๋“", shared_elec_df, ~์†Œ๋“, width="100%"),
       filter_select("๋™", "๋™", shared_elec_df, ~์๋ฉด๋™๋ช…)),
  d3scatter(shared_elec_df, ~์†Œ๋“, ~๊ธฐ์ดˆ์ˆ˜๊ธ‰์ž์ธ์›์ˆ˜, ~๋‹น์„ , width="100%", height=250),
  d3scatter(shared_elec_df, ~์†Œ๋“, ~๊ธฐ์ดˆ์ˆ˜๊ธ‰์ž์ธ์›์ˆ˜, ~๋‹น์„ , width="100%", height=250)
)
DT::datatable(shared_elec_dt, width="100%")